#include"preCmpH.h"
#define WIN32_LEAN_AND_MEAN
#include<Windows.h>
#include<WindowsX.h>
//
#include "UIManager.h"
//
#include<gl\GL.h>
#ifdef _DEBUG
#include<vld.h>
#endif

/* Global variables */
HWND hWnd;
HINSTANCE hInst;
char szWindowClass[] = "WinClass";
HANDLE consoleHandle;
int _w = 600;
int _h = 600;
static struct ui_opengl_settings
{
	HDC hDC;
	HGLRC hRC;
} OpenGLSettings;
LARGE_INTEGER timerStart;
LARGE_INTEGER timerStop;
LARGE_INTEGER timerDelta;
ui_manager::UIManager uiManager;
ui_manager::ui_graphics::UIImage* bg;
void defineUI(){
	ui_manager::ui_controls::UILabel* test = new ui_manager::ui_controls::UILabel();
	test->SetText("Label pt");

	ui_manager::ui_controls::UIButton* test2 = new ui_manager::ui_controls::UIButton();
	ui_manager::ui_graphics::UIImage* temp = &uiManager.getUIRenderer().LoadImageFromFile("button","res/button.png");
	test2->setBackground(temp);
	ui_manager::ui_graphics::UIImage* temp2 = &uiManager.getUIRenderer().LoadImageFromFile("button_hover","res/button_hover.png");
	test2->SetOnHoverImage(temp2);
	ui_manager::ui_graphics::UIImage* temp3 = &uiManager.getUIRenderer().LoadImageFromFile("button_click","res/button_click.png");
	test2->SetOnClickImage(temp3);
	test2->setPosition(UIPoint(200,200));
	test2->setSize(UISize(100,100));
	test2->GetLabel().SetText("Press me");

	ui_manager::ui_controls::UITextbox* test3 = new ui_manager::ui_controls::UITextbox();
	test3->setPosition(UIPoint(100,100));

	uiManager.Bind(test);
	uiManager.Bind(test2);
	uiManager.Bind(test3);
}

/* Function prototypes */
ATOM RegisterClassFn(HINSTANCE hInstance);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
void EnableOpenGL(HWND hwnd);
void DisableOpenGL(HWND hwnd);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    MSG msg;
	RegisterClassFn(hInstance);
	InitInstance (hInstance, nCmdShow);
	AllocConsole();
	AttachConsole(GetProcessId(hWnd));
	freopen( "CON", "w", stdout );
	std::cout << "testing one two three... BOOM !" << '\n';
	timerStart.QuadPart = 0;
	timerStop.QuadPart = 0;
	timerDelta.QuadPart = 0;
	EnableOpenGL(hWnd);
	//
	glewInit();
	//
	

	try{
		uiManager.StartUp();
		uiManager.getUIRenderer().setScreenSize(UISize(_w,_h));
		uiManager.getUIEventManager().getTimer().setInterval(500);
		uiManager.getUIEventManager().getTimer().Start();
		bg = &uiManager.getUIRenderer().LoadImageFromFile("background","res/bg.png");
		defineUI();
	}
	catch(UIException e){
		std::cout << e.what();
	}
	//
	BOOL quit = false;
	while(!quit)
	{
		if (PeekMessage( &msg, NULL, 0, 0 ,PM_REMOVE))
		{
			if(msg.message == WM_QUIT)
			{
				quit = true;
			}
			else
			{
				TranslateMessage(&msg); 
				DispatchMessage(&msg);
			}
		} else {
			QueryPerformanceCounter(&timerStart);
			try{
				glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
				uiManager.getUIRenderer().DrawImage(0,0,_w,_h,*bg);
				uiManager.getUIEventManager().getTimer().Update(timerDelta.QuadPart);
				uiManager.getUIEventManager().Polling();
				uiManager.ProcessEvents();
				SwapBuffers(OpenGLSettings.hDC);
				uiManager.getUIEventManager().getInputManager().SetButtonsStateChanged(false);
				uiManager.getUIEventManager().getInputManager().SetKeysStateChanged(false);
			}
			catch(std::exception& e){
				std::cout << e.what() << '\n';
			}
			QueryPerformanceCounter(&timerStop);
			timerDelta.QuadPart = timerStop.QuadPart - timerStart.QuadPart;

		}
	}
	DisableOpenGL(hWnd);
	FreeConsole();
	uiManager.ShutDown();
	return msg.wParam;
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{ 
   hInst = hInstance; 
   hWnd = CreateWindow(szWindowClass, "GUI Tester", WS_OVERLAPPEDWINDOW,
      0, 0, _w, _h, NULL, NULL, hInstance, NULL);
   SetWindowLong(hWnd, GWL_STYLE, 0);
   if (!hWnd)
   {
	   return FALSE;
   }
 
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
 
   return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int x = 0;
	int y = 0;
	switch(message){
		case WM_MOUSEMOVE:
		{
			x = GET_X_LPARAM(lParam);
			y = GET_Y_LPARAM(lParam);
			uiManager.getUIEventManager().getInputManager().SetMouseAbsCoordXY(x,y);
			break;
		}
		case WM_LBUTTONDOWN:
		{
			x = GET_X_LPARAM(lParam);
			y = GET_Y_LPARAM(lParam);
			uiManager.getUIEventManager().getInputManager().SetMouseAbsCoordXY(x,y);
			uiManager.getUIEventManager().getInputManager().SetMouseButtonState(
				ui_manager::ui_events::ui_input::BUTTON_LEFT,
				ui_manager::ui_events::ui_input::ACTION_DOWN);
			uiManager.getUIEventManager().getInputManager().SetButtonsStateChanged(true);
			break;
		}
		case WM_LBUTTONUP:
		{
			x = GET_X_LPARAM(lParam);
			y = GET_Y_LPARAM(lParam);
			uiManager.getUIEventManager().getInputManager().SetMouseAbsCoordXY(x,y);
			uiManager.getUIEventManager().getInputManager().SetMouseButtonState(
				ui_manager::ui_events::ui_input::BUTTON_LEFT,
				ui_manager::ui_events::ui_input::ACTION_UP);
			uiManager.getUIEventManager().getInputManager().SetButtonsStateChanged(true);
			break;
		}
		case WM_KEYDOWN:
		{
			if(wParam == VK_ESCAPE){
				PostQuitMessage(0);
			}
			uiManager.getUIEventManager().getInputManager().SetKeyState(
				ui_manager::ui_events::ui_input::GetMappedVirtualKey(wParam),
				ui_manager::ui_events::ui_input::ACTION_DOWN);
			uiManager.getUIEventManager().getInputManager().SetKeysStateChanged(true);
			break;
		}
		case WM_KEYUP:
		{
			uiManager.getUIEventManager().getInputManager().SetKeyState(
				ui_manager::ui_events::ui_input::GetMappedVirtualKey(wParam),
				ui_manager::ui_events::ui_input::ACTION_UP);
			uiManager.getUIEventManager().getInputManager().SetKeysStateChanged(true);
			break;
		}
		case WM_CLOSE:
		{
			DestroyWindow(hWnd);
			break;
		}
		case WM_DESTROY:
		{
			PostQuitMessage(0);
			break;
		}
		default:
		{
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
	}
	return 0;
}
ATOM RegisterClassFn(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX); 
 
    wcex.style          = NULL;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = NULL;
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = NULL;
 
    return RegisterClassEx(&wcex);
}
void EnableOpenGL(HWND hwnd)
{
    PIXELFORMATDESCRIPTOR pfd;

    int iFormat;

    /* get the device context (DC) */
	OpenGLSettings.hDC = GetDC(hwnd);

    /* set the pixel format for the DC */
    ZeroMemory(&pfd, sizeof(pfd));

    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 32;
    pfd.cDepthBits = 24;
	pfd.cStencilBits = 8;
    pfd.iLayerType = PFD_MAIN_PLANE;

    iFormat = ChoosePixelFormat(OpenGLSettings.hDC, &pfd);

    SetPixelFormat(OpenGLSettings.hDC, iFormat, &pfd);

    /* create and enable the render context (RC) */
	OpenGLSettings.hRC = wglCreateContext(OpenGLSettings.hDC);

	wglMakeCurrent(OpenGLSettings.hDC, OpenGLSettings.hRC);
}
void DisableOpenGL (HWND hwnd)
{
    wglMakeCurrent(NULL, NULL);
	wglDeleteContext(OpenGLSettings.hRC);
    ReleaseDC(hwnd, OpenGLSettings.hDC);
}